﻿using Castle.DynamicProxy;
using Net8.Project.Model.AOP;
using Newtonsoft.Json;
using System.Reflection;

namespace Net8.Project.Extension
{
    /// <summary>
    /// AOP服务层拦截器，实现IInterceptor接口
    /// 用于方法调用前后自动记录日志、异常等
    /// </summary>
    public class AOPServiceInterceptor : IInterceptor
    {
        /// <summary>
        /// 是否输出日志，默认为false
        /// </summary>
        public bool IsWriteLog { get; set; } = false;
        /// <summary>
        /// 拦截方法，AOP切面逻辑入口
        /// </summary>
        /// <param name="invocation">包含被拦截方法的信息</param>
        public void Intercept(IInvocation invocation)
        {
            string json;
            try
            {
                // 序列化方法参数
                json = JsonConvert.SerializeObject(invocation.Arguments);
            }
            catch (Exception ex)
            {
                json = "无法序列化参数，可能是Lambda表达式等原因：" + ex;
            }

            DateTime startTime = DateTime.Now;
            // 构造日志信息对象
            InterceptorLogInfo apiLogAopInfo = new InterceptorLogInfo
            {
                RequestTime = startTime.ToString("yyyy-MM-dd HH:mm:ss fff"),
                OpUserName = "",
                RequestMethodName = invocation.Method.Name,
                RequestParamsName = string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString())),
                ResponseJsonData = json
            };

            try
            {
                // 执行被拦截的方法
                invocation.Proceed();

                // 判断是否为异步方法
                if (IsAsyncMethod(invocation.Method))
                {
                    // Task
                    if (invocation.Method.ReturnType == typeof(Task))
                    {
                        invocation.ReturnValue = InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(
                            (Task)invocation.ReturnValue,
                            async () => await SuccessAction(invocation, apiLogAopInfo, startTime),
                            ex => LogEx(ex, apiLogAopInfo));
                    }
                    // Task<TResult>
                    else
                    {
                        invocation.ReturnValue = InternalAsyncHelper.CallAwaitTaskWithPostActionAndFinallyAndGetResult(
                            invocation.Method.ReturnType.GenericTypeArguments[0],
                            invocation.ReturnValue,
                            async (o) => await SuccessAction(invocation, apiLogAopInfo, startTime, o),
                            ex => LogEx(ex, apiLogAopInfo));
                    }
                }
                else
                {
                    // 同步方法，记录返回值
                    string jsonResult;
                    try
                    {
                        jsonResult = JsonConvert.SerializeObject(invocation.ReturnValue);
                    }
                    catch (Exception ex)
                    {
                        jsonResult = "无法序列化返回值：" + ex;
                    }

                    DateTime endTime = DateTime.Now;
                    string responseTime = (endTime - startTime).TotalMilliseconds.ToString("F0");
                    apiLogAopInfo.ResponseTime = endTime.ToString("yyyy-MM-dd HH:mm:ss fff");
                    apiLogAopInfo.ResponseIntervalTime = responseTime + "ms";
                    apiLogAopInfo.ResponseJsonData = jsonResult;
                    // 可以根据需要输出日志
                    if (IsWriteLog) Console.WriteLine(JsonConvert.SerializeObject(apiLogAopInfo));
                }
            }
            catch (Exception ex)
            {
                // 捕获异常并记录
                LogEx(ex, apiLogAopInfo);
                throw;
            }
        }

        /// <summary>
        /// 异步方法成功后执行的日志记录
        /// </summary>
        private async Task SuccessAction(IInvocation invocation, InterceptorLogInfo apiLogAopInfo, DateTime startTime, object o = null)
        {
            DateTime endTime = DateTime.Now;
            string responseTime = (endTime - startTime).TotalMilliseconds.ToString("F0");
            apiLogAopInfo.ResponseTime = endTime.ToString("yyyy-MM-dd HH:mm:ss fff");
            apiLogAopInfo.ResponseIntervalTime = responseTime + "ms";
            apiLogAopInfo.ResponseJsonData = JsonConvert.SerializeObject(o);

            await Task.Run(() =>
            {
                if (IsWriteLog) Console.WriteLine("执行成功-->" + JsonConvert.SerializeObject(apiLogAopInfo));
            });
        }

        /// <summary>
        /// 记录异常日志
        /// </summary>
        private void LogEx(Exception ex, InterceptorLogInfo dataIntercept)
        {
            if (ex != null)
            {
                if (IsWriteLog) Console.WriteLine("error!!!:" + ex.Message + JsonConvert.SerializeObject(dataIntercept));
            }
        }

        /// <summary>
        /// 判断方法是否为异步方法（Task或Task&lt;T&gt;）
        /// </summary>
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return method.ReturnType == typeof(Task) ||
                   (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>));
        }
    }

    /// <summary>
    /// 异步辅助类，处理异步方法的后置操作和异常
    /// </summary>
    internal static class InternalAsyncHelper
    {
        /// <summary>
        /// 等待Task执行，执行后置操作和异常处理
        /// </summary>
        public static async Task AwaitTaskWithPostActionAndFinally(Task actualReturnValue, Func<Task> postAction, Action<Exception> finalAction)
        {
            Exception exception = null;
            try
            {
                await actualReturnValue;
                await postAction();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            finally
            {
                finalAction(exception);
            }
        }

        /// <summary>
        /// 等待Task&lt;T&gt;执行，执行后置操作和异常处理，并返回结果
        /// </summary>
        public static async Task<T> AwaitTaskWithPostActionAndFinallyAndGetResult<T>(Task<T> actualReturnValue, Func<object, Task> postAction,
            Action<Exception> finalAction)
        {
            Exception exception = null;
            try
            {
                var result = await actualReturnValue;
                await postAction(result);
                return result;
            }
            catch (Exception ex)
            {
                exception = ex;
                throw;
            }
            finally
            {
                finalAction(exception);
            }
        }

        /// <summary>
        /// 反射调用泛型方法，适配Task&lt;T&gt;的动态类型
        /// </summary>
        public static object CallAwaitTaskWithPostActionAndFinallyAndGetResult(Type taskReturnType, object actualReturnValue,
             Func<object, Task> action, Action<Exception> finalAction)
        {
            return typeof(InternalAsyncHelper)
                .GetMethod(nameof(AwaitTaskWithPostActionAndFinallyAndGetResult), BindingFlags.Public | BindingFlags.Static)
                .MakeGenericMethod(taskReturnType)
                .Invoke(null, new object[] { actualReturnValue, action, finalAction });
        }
    }
}
